package be.pluyckx.batteryprogress.components.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

import be.pluyckx.batteryprogress.R;

/**
 * Created by Philip Luyckx on 15/08/13.
 */
public class NumberPicker extends FrameLayout {
  private static final Handler mUiThreadHandler = new Handler();
  private EditText mTvValue;
  private Button mBIncrease;
  private Button mBDecrease;
  private int mMin = 0;
  private int mMax = 0;
  private int mValue = 0;
  private int mStep = 1;
  private List<DataListener> mDataListeners = new ArrayList<DataListener>();

  public NumberPicker(Context context) {
    super(context);
    init(null);
  }

  public NumberPicker(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(attrs);
  }

  public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(attrs);
  }

  private void init(AttributeSet attrs) {
    View view = inflate(this.getContext(), R.layout.view_numberpicker, this);
    mTvValue = (EditText) view.findViewById(R.id.np_value);
    mBIncrease = (Button) view.findViewById(R.id.np_increase);
    mBDecrease = (Button) view.findViewById(R.id.np_decrease);
    mBIncrease.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View view) {
        setValue(mValue + mStep);
      }
    });
    mBDecrease.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View view) {
        setValue(mValue - mStep);
      }
    });
    mTvValue.addTextChangedListener(new TextWatcher() {
      @Override
      public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {

      }

      @Override
      public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {

      }

      @Override
      public void afterTextChanged(Editable editable) {
        setValue(parseIntFromView(editable), false);
      }
    });
    mTvValue.setOnEditorActionListener(new TextView.OnEditorActionListener() {
      @Override
      public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
        if (actionId == EditorInfo.IME_ACTION_DONE || (keyEvent.getAction() == KeyEvent.ACTION_DOWN && keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
          updateView();
        }

        return false;
      }
    });

    addDataListener(new DataListener() {
      @Override
      public void onValueChanged(int value) {
        updateButtons();
      }
    });

    if (attrs != null) {
      TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.NumberPicker, 0, 0);
      try {
        setMax(a.getInteger(R.styleable.NumberPicker_max, Integer.MAX_VALUE));
        setMin(a.getInteger(R.styleable.NumberPicker_min, Integer.MIN_VALUE));
        setValue(a.getInteger(R.styleable.NumberPicker_value, 0));
        setStep(a.getInteger(R.styleable.NumberPicker_step, 1));
      } finally {
        a.recycle();
      }
    }
  }

  private void updateButtons() {
    mBDecrease.setEnabled(canDecrease());
    mBIncrease.setEnabled(canIncrease());
  }

  public int getMin() {
    return mMin;
  }

  public void setMin(int value) {
    if (mMin != value) {
      if (value > mMax) {
        setMax(value);
      }

      mMin = value;

      if (mValue < mMin) {
        setValue(mMin);
      } else {
        updateButtons();
      }
    }
  }

  public int getMax() {
    return mMax;
  }

  public void setMax(int value) {
    if (mMax != value) {
      if (mMin > value) {
        setMin(value);
      }

      mMax = value;

      if (mValue > mMax) {
        setValue(mMax);
      } else {
        updateButtons();
      }
    }
  }

  public int getValue() {
    return mValue;
  }

  public void setValue(int value) {
    setValue(value, true);
  }

  private void setValue(int value, boolean updateView) {

    if (value < mMin) {
      value = mMin;
    } else if (value > mMax) {
      value = mMax;
    }

    if (mValue != value) {
      mValue = value;
      if (updateView) {
        updateView();
      }
      fireValueChanged(mValue);
    }
  }

  private int parseIntFromView(CharSequence text) {
    String str = text.toString();
    return (str.equals("") ? 0 : Integer.parseInt(str));
  }

  private void updateView() {
    final int value = parseIntFromView(mTvValue.getText());
    if (value != mValue) {
      mUiThreadHandler.post(new Runnable() {
        @Override
        public void run() {
          mTvValue.setText(Integer.toString(mValue));
        }
      });
    }
  }

  public int getStep() {
    return mStep;
  }

  public void setStep(int value) {
    mStep = value;

    if (mStep < 1) {
      throw new IllegalArgumentException("Step < 1");
    }
  }

  public void inc() {
    setValue(mValue + mStep);
  }

  public void dec() {
    setValue(mValue - mStep);
  }

  public boolean canIncrease() {
    return mValue < mMax;
  }

  public boolean canDecrease() {
    return mValue > mMin;
  }

  public void addDataListener(DataListener listener) {
    mDataListeners.add(listener);
  }

  public void removeDataListener(DataListener listener) {
    mDataListeners.remove(listener);
  }

  private void fireValueChanged(int value) {
    for (DataListener l : mDataListeners) {
      l.onValueChanged(value);
    }
  }

  public interface DataListener {
    public void onValueChanged(int value);
  }
}
